﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DrivingCRM.Model;

namespace DrivingCRM.Controller
{
    public static class EntityManager
    {
        /// <summary>
        /// Méthode gérant l'ajout en base d'une adresse
        /// </summary>
        /// <param name="number"></param>
        /// <param name="streetTypeId"></param>
        /// <param name="streetName"></param>
        /// <param name="extra"></param>
        /// <param name="zipcode"></param>
        /// <param name="city"></param>
        /// <param name="cedex"></param>
        /// <returns></returns>
        public static Address AddAdress(string number, int streetTypeId, string streetName, string extra, string zipcode, string city, string cedex)
        {
            try
            {
                Address ret = null;

                /// vérification des champs requis
                if (number != null && streetTypeId != null && streetName != null && zipcode != null && city != null)
                {
                    /// vérification du numéro, du code postale et du cédex
                    int num = int.Parse(number);
                    int zip = int.Parse(zipcode);

                    /// vérification de l'existence de l'adresse en base 
                    /// && add.StreetType == streetType
                    Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();
                    List<Address> existingAddress = (from add in database.AddressSet
                                                 where add.Number == num && add.StreetName == streetName
                                                 && add.Zipcode == zip && add.City == city && add.StreetTypeId == streetTypeId
                                                select add).ToList();

                    Model_DrivingCRMContainer databaseStreet = new Model_DrivingCRMContainer();
                    string streetTypeString = (from type in databaseStreet.StreetTypeSet
                                               where type.Id == streetTypeId
                                               select type.Type).First();

                    /// si l'adresse n'existe pas elle sera créée
                    if (existingAddress.Count == 0)
                    {
                        string completeAddress = num.ToString() + " " + streetTypeString + " " + streetName;

                        if (extra != null)
                            completeAddress += " " + extra;

                        completeAddress += " " + zip + " " + city;

                        ret = new Address();
                        ret.Number = num;
                        ret.StreetTypeId = streetTypeId;
                        ret.StreetName = streetName;
                        ret.Zipcode = zip;
                        ret.City = city;
                        ret.Extra = extra;

                        /// gestion du cédex
                        if (cedex != null && cedex != string.Empty)
                        {
                            ret.Cedex = int.Parse(cedex);
                            completeAddress += " Cédex " + cedex;
                        }
                        else
                            ret.Cedex = null;

                        ret.CompleteAddress = completeAddress;

                        /// ajout et sauvegarde
                        database.AddToAddressSet(ret);
                        database.SaveChanges();
                        int test = ret.IdAdress;
                    }
                    else
                        ret = existingAddress.First();
                }

                return ret;
            }
            catch (Exception ex)
            {

                return null;
            }
        }

        /// <summary>
        /// Méthode gérant l'ajout d'un évènement en base
        /// </summary>
        /// <param name="name"></param>
        /// <param name="type"></param>
        /// <param name="duration"></param>
        /// <param name="dateWithHour"></param>
        /// <param name="stakeholderId"></param>
        /// <param name="agencyIdAgency"></param>
        /// <returns></returns>
        public static string AddEvent(string type, int duration, DateTime dateWithHour, Guid stakeholderId, int agencyIdAgency)
        {
            try
            {
                string ret = string.Empty;

                DateTime endDate = dateWithHour.AddHours(duration);

                ///récupération du nom complet de l'intervenant
                Model_DrivingCRMContainer databaseStake = new Model_DrivingCRMContainer();
                string completeStakeholder = (from sta in databaseStake.UserSet
                                              where sta.Id == stakeholderId
                                              select sta.CompleteName).First();

                string completeEvent = type + " de " + duration.ToString() + " le " + string.Format("{0:dd/MM/yyyy}", dateWithHour) + " à " + string.Format("{0:hh:mm}", dateWithHour) + " avec " + completeStakeholder;

                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();

                ///vérification de la non existence d'un évènement en conflit (stakeholder ou véhicule non disponible) à faire

                database.AddToEventSet(new Event() { Type = type, Duration = duration, DateWithHour = dateWithHour, StakeholderId = stakeholderId, AgencyIdAgency = agencyIdAgency, EndDateWithHour = endDate, CompleteEvent = completeEvent });

                database.SaveChanges();

                ret = "No error";

                return ret;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        /// <summary>
        /// Méthode gérant l'ajout d'une note en base
        /// </summary>
        /// <param name="dateWithHour"></param>
        /// <param name="value"></param>
        /// <param name="eventIdEvent"></param>
        /// <param name="clientId"></param>
        /// <returns></returns>
        public static string AddMark(DateTime dateWithHour, int value, int eventIdEvent, Guid clientId)
        {
            try
            {
                string ret = string.Empty;

                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();

                database.AddToMarkSet(new Mark() { MarkingDate = dateWithHour, Value = value, EventIdEvent = eventIdEvent, ClientId = clientId });


                var completeClient = (from usr in database.UserSet
                                      where usr.Id == clientId
                                      select usr).First();
                int eventduration = (from ev in database.EventSet
                                     where ev.IdEvent == eventIdEvent
                                     select ev.Duration).First();


                ((Client)completeClient).RemainingHours = ((Client)completeClient).RemainingHours - eventduration;

                if (((Client)completeClient).RemainingHours < 0)
                {
                    ((Client)completeClient).RemainingHours = 0;
                }

                database.SaveChanges();

                ret = "No error";

                return ret;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        /// <summary>
        /// Méthode gérant l'ajout d'un article en base
        /// </summary>
        /// <param name="title"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string AddArticle(string title, string content, string category)
        {
            try
            {
                string ret = "Erreur lors de l'insertion d'un article";

                if (!string.IsNullOrEmpty(title) && !string.IsNullOrEmpty(content) && !string.IsNullOrEmpty(category))
                {

                    Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();

                    database.AddToArticleSet(new Article() { Title = title, Content = content, Category = category });

                    database.SaveChanges();

                    ret = "No error";
                }

                return ret;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }


        /// <summary>
        /// Méthode gérant l'ajout d'un post du forum en base
        /// </summary>
        /// <param name="title"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string AddPost(string title, string content, DateTime creationDate, int discussionId, Guid userId)
        {
            try
            {
                string ret = string.Empty;

                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();

                database.AddToPostSet(new Post() { Title = title, Content = content, CreationDate = creationDate, DiscussionIdDiscussion = discussionId, UserId = userId});

                database.SaveChanges();

                ret = "No error";

                return ret;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }
        /// <summary>
        /// méthode permettant l'ajout d'une discussion
        /// </summary>
        /// <param name="title"></param>
        /// <param name="description"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public static string AddDiscussion(string title, string description, Guid userId)
        {
            try
            {
                string ret = string.Empty;

                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();

                database.AddToDiscussionSet(new Discussion() { Title = title, Description = description, UserId = userId });

                database.SaveChanges();

                ret = "No error";

                return ret;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }


        /// <summary>
        /// Méthode retournant le type de l'utilisateur en paramètre
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public static List<string> GetCurrentUserType(string username)
        {
            try
            {
                List<string> ret = null;

                /// récupération de tous les utilisateurs ayant ce username là
                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();
                var existingUsers = from usr in database.UserSet
                                    where usr.Username == username
                                    select usr;

                /// s'il n'y a qu'un utilisateur
                if (existingUsers.Count() == 1)
                {
                    if (existingUsers.First() is Administrator)
                    {
                        ret = new List<string>(2);
                        ret.Add("Administrator");
                        ret.Add((existingUsers.First() as Administrator).CompleteName);
                    }
                    else if (existingUsers.First() is Stakeholder)
                    {
                        ret = new List<string>(3);
                        ret.Add("Stakeholder");
                        ret.Add((existingUsers.First() as Stakeholder).CompleteName);

                        ret.Add((existingUsers.First() as Stakeholder).AgencyIdAgency.ToString());
                    }
                    else if (existingUsers.First() is Salesman)
                    {
                        ret = new List<string>(3);
                        ret.Add("Salesman");
                        ret.Add((existingUsers.First() as Salesman).CompleteName);

                        ret.Add((existingUsers.First() as Salesman).AgencyIdAgency.ToString());
                    }
                    else if (existingUsers.First() is Client)
                    {
                        ret = new List<string>(3);
                        ret.Add("Client");
                        ret.Add((existingUsers.First() as Client).CompleteName);

                        ret.Add((existingUsers.First() as Client).AgencyIdAgency.ToString());
                    }
                    else
                    {
                        ret = new List<string>(1);
                        ret.Add("Erreur: le type de l'utilisateur n'a pu être trouvé");
                    }
                }
                else
                {
                    ret = new List<string>(1);
                    ret.Add("Erreur: plusieurs utilisateurs ont le même nom d'utilisateur");
                }

                return ret;
            }
            catch (Exception ex)
            {
                List<string> reterr = new List<string>(1);
                reterr.Add(string.Format("Erreur: une exception est survenue lors de la tentative de récupération du type de l'utilisateur '{0}'.", username));
                return reterr;
            }
        }

        /// <summary>
        /// Méthode permettant l'inscription d'un client à un évènement
        /// </summary>
        /// <param name="eventId"></param>
        /// <param name="inscriptionDate"></param>
        /// <param name="clientId"></param>
        /// <returns></returns>
        public static string AddEventInscription(int eventId, DateTime inscriptionDate, Guid clientId)
        {
            try
            {
                string ret = "Inscription effectuée";

                ///list la liste des event
                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();
                List<Event> existingEvent = (from ev in database.EventSet
                                             where ev.IdEvent == eventId
                                             select ev).ToList();
                //récupération du type d'event;
                Event boundEvent = (from ty in database.EventSet
                           where ty.IdEvent == eventId
                           select ty).First();

                bool inWait = true;


                ///vérification que l'event existe bien
                if (existingEvent.Count == 1)
                {


                    IQueryable<EventInscription> idEventInscription = from evI in database.EventInscriptionSet.Include("Event")
                                              where evI.ClientId == clientId && evI.Event.DateWithHour >= boundEvent.DateWithHour && evI.Event.DateWithHour <= boundEvent.EndDateWithHour
                                              select evI;

                    if (idEventInscription.Count() == 0)
                    {

                        List<EventInscription> existingInscription = (from ei in database.EventInscriptionSet
                                                                      where ei.EventIdEvent == eventId
                                                                      select ei).ToList();

                        if (boundEvent.Type.Equals("Cours sur plateau") && existingInscription.Count < 4)
                        {
                            inWait = false;
                        }
                        else if (boundEvent.Type.Equals("Examen de code") && existingInscription.Count < 5)
                        {
                            inWait = false;
                        }
                        else if (boundEvent.Type.Equals("Examen du plateau") && existingInscription.Count < 4)
                        {
                            inWait = false;
                        }
                        else if (boundEvent.Type.Equals("Examen de conduite") && existingInscription.Count < 3)
                        {
                            inWait = false;
                        }
                        else if (boundEvent.Type.Equals("Cours de conduite") && existingInscription.Count < 3)
                        {
                            inWait = false;
                        }
                        else if (boundEvent.Type.Equals("Cours de code") && existingInscription.Count < 10)
                        {
                            inWait = false;
                        }
                        else
                            return "Erreur le type d'évènement n'existe pas";

                        if (inWait)
                            ret = "Inscription effectuée (en file d'attente)";

                        database.AddToEventInscriptionSet(new EventInscription() { EventIdEvent = eventId, InscriptionDate = inscriptionDate, InWait = inWait, ClientId = clientId });

                        database.SaveChanges();
                    }
                    else
                    {
                        ret = "vous êtes déjà inscrit";
                    }
                }
                else
                {
                    ret = "L'évènement n'a pas été trouvé";
                }

                return ret;
            }
            catch (Exception ex)
            {
                return "Une erreur est survenue lors de l'inscription à un évènement.";
            }

        }
        
        /// <summary>
        /// Méthode permettant la suppresion d'un évènement en base
        /// </summary>
        /// <param name="idEvent"></param>
        /// <returns></returns>
        public static bool DeleteEvent(int idEvent)
        {
            try
            {
                bool ret = false;

                /// recherche de l'évènement en base
                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();
                Event eventToDelete = (from ev in database.EventSet
                                       where ev.IdEvent == idEvent
                                       select ev).First();

                /// Vérification s'il n'y a pas des inscriptions liées à l'évènement
                IQueryable<EventInscription> existingsInscriptions = from evInsc in database.EventInscriptionSet
                                                                     where evInsc.EventIdEvent == idEvent
                                                                     select evInsc;

                if (existingsInscriptions.Count() == 0)
                {
                    database.DeleteObject(eventToDelete);
                    database.SaveChanges();
                    ret = true;
                }

                return ret;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        
        /// <summary>
        /// Méthode permettant de définir le nombre d'heures d'un client
        /// </summary>
        /// <param name="totalHours"></param>
        /// <param name="idClient"></param>
        /// <returns></returns>
        public static string DefineTotalHours(int totalHours, Guid idClient)
        {
            try
            {
                string ret = string.Empty;

                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();

                var completeClient = (from usr in database.UserSet
                                      where usr.Id == idClient
                                      select usr).First();

                ((Client)completeClient).TotalHours = totalHours;
                ((Client)completeClient).RemainingHours = totalHours;

                database.SaveChanges();

                ret = "No error";

                return ret;
            }
            catch (Exception ex)
            {
                return "Erreur lors de la mise à jour des heures d'un client";
            }
          
        }

        /// <summary>
        /// Méthode de mise en révision d'un véhicule
        /// </summary>
        /// <param name="idVehicule"></param>
        /// <param name="lastRevision"></param>
        /// <returns></returns>
        public static string PutInRevision(int idVehicule, DateTime lastRevision)
        {
            try
            {
                string ret = string.Empty;

                Model_DrivingCRMContainer database = new Model_DrivingCRMContainer();

                var currentVehicule = (from car in database.VehicleSet
                                      where car.IdVehicle == idVehicule
                                      select car).First();

                ((Vehicle)currentVehicule).LastRevisionDate = lastRevision;
                

                database.SaveChanges();

                ret = "No error";

                return ret;
            }
            catch (Exception ex)
            {
                return "Erreur lors de la mise en révision du véhicule.";
            }
        }

    }
}
